package com.sleepcamel.exporter.mappingGenerator;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.apache.commons.lang3.StringUtils;

import com.sleepcamel.rest.domain.JavaClass;
import com.sleepcamel.rest.domain.JavaProperty;
import com.sleepcamel.rest.domain.Mapping;
import com.sleepcamel.rest.domain.Path;
import com.sleepcamel.rest.domain.method.RESTMethod;
import com.sleepcamel.rest.domain.method.RESTMethodType;
import com.sleepcamel.rest.domain.method.parameter.MethodParameter;
import com.sleepcamel.rest.domain.method.parameter.RESTMethodParameter;
import com.sleepcamel.rest.domain.method.parameter.RESTMethodParameterType;
import com.sleepcamel.rest.domain.method.parameter.RESTMethodParameterTypeName;

public class DomainJavaClassToMapping {

	private JavaClass domainClass;

	public DomainJavaClassToMapping(JavaClass domainClass) {
		this.domainClass = domainClass;
	}
	
	public Mapping getMapping(){
		Mapping mapping = new Mapping();
		String domainClassName = domainClass.getName();
		mapping.setName(domainClassName+"Service");
		mapping.setPath(new Path(domainClassName.toLowerCase()));
		
		mapping.addChilds(generateClassMethods());
		
		mapping.addChilds(generateInstanceMethods());
		
		mapping.addChilds(generateFieldMethods(domainClass.getAllProperties()));
		
		return mapping;
	}

	private Collection<RESTMethod> generateClassMethods() {
		List<RESTMethod> methods = new ArrayList<RESTMethod>();

		String entityGroupNameLowerCase = StringUtils.uncapitalize(domainClass.getName()+"s");
		String entityGroupName = StringUtils.capitalize(entityGroupNameLowerCase);

		RESTMethod restMethod = new RESTMethod();
		restMethod.setType(RESTMethodType.GET);
		restMethod.setName("get"+entityGroupName);
		restMethod.setReturnType(domainClass.asList());
		restMethod.setPath(new Path());
		methods.add(restMethod);
		
		restMethod = new RESTMethod();
		restMethod.setType(RESTMethodType.PUT);
		restMethod.setName("put"+entityGroupName);
		restMethod.setReturnType(JavaClass.voidClass);
		restMethod.setPath(new Path());
		
		MethodParameter methodParameter = new MethodParameter();
		methodParameter.setName(entityGroupNameLowerCase);
		methodParameter.setType(domainClass.asList());
		restMethod.addParameter(methodParameter);
		
		methods.add(restMethod);
		
		restMethod = new RESTMethod();
		restMethod.setType(RESTMethodType.POST);
		restMethod.setName("post"+entityGroupName);
		restMethod.setReturnType(JavaClass.voidClass);
		restMethod.setPath(new Path());
		
		methodParameter = new MethodParameter();
		methodParameter.setName(entityGroupNameLowerCase);
		methodParameter.setType(domainClass.asList());
		restMethod.addParameter(methodParameter);
		
		methods.add(restMethod);
		
		restMethod = new RESTMethod();
		restMethod.setType(RESTMethodType.DELETE);
		restMethod.setName("delete"+entityGroupName);
		restMethod.setReturnType(new JavaClass("void"));
		restMethod.setPath(new Path());
		
		methods.add(restMethod);
		return methods;
	}

	private Collection<RESTMethod> generateInstanceMethods() {
		List<RESTMethod> methods = new ArrayList<RESTMethod>();
		
		String entityName = StringUtils.capitalize(domainClass.getName());
		String entityNameLowerCase = StringUtils.uncapitalize(domainClass.getName());

		RESTMethod restMethod = new RESTMethod();
		restMethod.setType(RESTMethodType.GET);
		restMethod.setName("get"+entityName);
		restMethod.setReturnType(domainClass);
		restMethod.setPath(new Path("{id}"));
		
		RESTMethodParameter idParameter = new RESTMethodParameter();
		idParameter.setName("id");
		idParameter.setType(domainClass.getId().getJavaClass());
		RESTMethodParameterType restMethodParameterType = new RESTMethodParameterType(RESTMethodParameterTypeName.PathParam);
		restMethodParameterType.setValue("id");
		idParameter.setRestParameterType(restMethodParameterType);
		restMethod.addParameter(idParameter);

		methods.add(restMethod);
		
		restMethod = new RESTMethod();
		restMethod.setType(RESTMethodType.PUT);
		restMethod.setName("put"+entityName);
		restMethod.setReturnType(domainClass);
		restMethod.setPath(new Path("{id}"));
		idParameter = new RESTMethodParameter();
		idParameter.setName("id");
		idParameter.setType(domainClass.getId().getJavaClass());
		restMethodParameterType = new RESTMethodParameterType(RESTMethodParameterTypeName.PathParam);
		restMethodParameterType.setValue("id");
		idParameter.setRestParameterType(restMethodParameterType);
		restMethod.addParameter(idParameter);
		
		methods.add(restMethod);
		
		restMethod = new RESTMethod();
		restMethod.setType(RESTMethodType.POST);
		restMethod.setName("post"+entityName);
		restMethod.setReturnType(domainClass);
		restMethod.setPath(new Path("{id}"));
		
		idParameter = new RESTMethodParameter();
		idParameter.setName("id");
		idParameter.setType(domainClass.getId().getJavaClass());
		restMethodParameterType = new RESTMethodParameterType(RESTMethodParameterTypeName.PathParam);
		restMethodParameterType.setValue("id");
		idParameter.setRestParameterType(restMethodParameterType);
		restMethod.addParameter(idParameter);
		
		methods.add(restMethod);
		
		restMethod = new RESTMethod();
		restMethod.setType(RESTMethodType.DELETE);
		restMethod.setName("delete"+entityName);
		restMethod.setReturnType(JavaClass.voidClass);
		restMethod.setPath(new Path("{id}"));
		
		idParameter = new RESTMethodParameter();
		idParameter.setName("id");
		idParameter.setType(domainClass.getId().getJavaClass());
		restMethodParameterType = new RESTMethodParameterType(RESTMethodParameterTypeName.PathParam);
		restMethodParameterType.setValue("id");
		idParameter.setRestParameterType(restMethodParameterType);
		restMethod.addParameter(idParameter);
		
		methods.add(restMethod);
		
		return methods;
	}
	
	private Collection<RESTMethod> generateFieldMethods(List<? extends JavaProperty> list) {
		List<RESTMethod> methods = new ArrayList<RESTMethod>();
		
		for(JavaProperty field:list){
			methods.addAll(generateMethodsForField(field));
		}

		return methods;
	}

	private Collection<RESTMethod> generateMethodsForField(JavaProperty field) {
		List<RESTMethod> methods = new ArrayList<RESTMethod>();
		String fieldName = field.getName();
		JavaClass type = field.getJavaClass();
		String titleFieldName = StringUtils.capitalize(fieldName);

		RESTMethod restMethod = new RESTMethod();
		restMethod.setType(RESTMethodType.GET);
		restMethod.setName("get"+titleFieldName+"Field");
		restMethod.setReturnType(type);
		restMethod.setPath(new Path("{id}/"+field.getName().toLowerCase()));
		
		RESTMethodParameter idParameter = new RESTMethodParameter();
		idParameter.setName("id");
		idParameter.setType(domainClass.getId().getJavaClass());
		RESTMethodParameterType restMethodParameterType = new RESTMethodParameterType(RESTMethodParameterTypeName.PathParam);
		restMethodParameterType.setValue("id");
		idParameter.setRestParameterType(restMethodParameterType);
		restMethod.addParameter(idParameter);
		methods.add(restMethod);
		
		restMethod = new RESTMethod();
		restMethod.setType(RESTMethodType.PUT);
		restMethod.setName("put"+titleFieldName+"Field");
		restMethod.setReturnType(type);
		restMethod.setPath(new Path("{id}/"+field.getName().toLowerCase()));
		
		idParameter = new RESTMethodParameter();
		idParameter.setName("id");
		idParameter.setType(domainClass.getId().getJavaClass());
		restMethodParameterType = new RESTMethodParameterType(RESTMethodParameterTypeName.PathParam);
		restMethodParameterType.setValue("id");
		idParameter.setRestParameterType(restMethodParameterType);
		restMethod.addParameter(idParameter);
		methods.add(restMethod);
		
		restMethod = new RESTMethod();
		restMethod.setType(RESTMethodType.POST);
		restMethod.setName("post"+titleFieldName+"Field");
		restMethod.setReturnType(type);
		restMethod.setPath(new Path("{id}/"+field.getName().toLowerCase()));
		
		idParameter = new RESTMethodParameter();
		idParameter.setName("id");
		idParameter.setType(domainClass.getId().getJavaClass());
		restMethodParameterType = new RESTMethodParameterType(RESTMethodParameterTypeName.PathParam);
		restMethodParameterType.setValue("id");
		idParameter.setRestParameterType(restMethodParameterType);
		restMethod.addParameter(idParameter);
		methods.add(restMethod);
		
		restMethod = new RESTMethod();
		restMethod.setType(RESTMethodType.DELETE);
		restMethod.setName("delete"+titleFieldName+"Field");
		restMethod.setReturnType(JavaClass.voidClass);
		restMethod.setPath(new Path("{id}/"+field.getName().toLowerCase()));
		
		idParameter = new RESTMethodParameter();
		idParameter.setName("id");
		idParameter.setType(domainClass.getId().getJavaClass());
		restMethodParameterType = new RESTMethodParameterType(RESTMethodParameterTypeName.PathParam);
		restMethodParameterType.setValue("id");
		idParameter.setRestParameterType(restMethodParameterType);
		restMethod.addParameter(idParameter);
		methods.add(restMethod);
		
		return methods;
	}

}
